package com.lzugis.controller;

import com.lzugis.utils.FileUtil;
import io.swagger.annotations.Api;
import org.locationtech.jts.geom.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.wowtools.giscat.vector.mvt.MvtBuilder;
import org.wowtools.giscat.vector.mvt.MvtLayer;
import org.wowtools.giscat.vector.pojo.Feature;
import org.wowtools.giscat.vector.pojo.FeatureCollection;
import org.wowtools.giscat.vector.pojo.converter.GeoJsonFeatureConverter;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Api(tags = "矢量切片")
@RestController
@RequestMapping("tile")
public class MvtController {
    private static final FeatureCollection areaFeatureCollection;//面数据
    private static final FeatureCollection lineFeatureCollection;//线数据
    private static final FeatureCollection pointFeatureCollection;//点数据
    private static final GeometryFactory geometryFactory = new GeometryFactory();
    private static final FileUtil fileUtil = new FileUtil();

    static {
        //构造示例数据
        GeometryFactory gf = new GeometryFactory();
        String strJson = fileUtil.getFileContent("E:\\year2022\\learn\\spring-boot-demo\\src\\main\\resources\\data\\province.geojson");
        areaFeatureCollection = GeoJsonFeatureConverter.fromGeoJsonFeatureCollection(strJson, gf);
        ArrayList<Feature> pointFeatures = new ArrayList<>(areaFeatureCollection.getFeatures().size());
        ArrayList<Feature> lineFeatures = new ArrayList<>(areaFeatureCollection.getFeatures().size());
        for (Feature feature : areaFeatureCollection.getFeatures()) {
            Feature pointFeature = new Feature();
            ArrayList center = (ArrayList) feature.getProperties().get("center");
            if (center != null) {
                Point point = gf.createPoint(new Coordinate((Double) center.get(0), (Double) center.get(1)));
                Map map = new HashMap();
                map.put("name", feature.getProperties().get("name"));
                pointFeature.setProperties(map);
                pointFeature.setGeometry(point);
                pointFeatures.add(pointFeature);
            }
            Feature lineFeature = new Feature();
            if (feature.getGeometry() instanceof MultiPolygon) {
                MultiPolygon multiPolygon = (MultiPolygon) feature.getGeometry();
                LineString[] lines = new LineString[multiPolygon.getNumGeometries()];
                for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
                    Polygon polygon = (Polygon) multiPolygon.getGeometryN(i);
                    lines[i] = gf.createLineString(polygon.getExteriorRing().getCoordinates());
                }
                MultiLineString ml = gf.createMultiLineString(lines);
                lineFeature.setGeometry(ml);
            } else {
                LineString line = gf.createLineString(feature.getGeometry().getCoordinates());
                lineFeature.setGeometry(line);
            }
            lineFeatures.add(lineFeature);
        }
        lineFeatureCollection = new FeatureCollection();
        lineFeatureCollection.setFeatures(lineFeatures);
        pointFeatureCollection = new FeatureCollection();
        pointFeatureCollection.setFeatures(pointFeatures);
    }

    @RequestMapping("/{z}/{x}/{y}")
    public void getTile(@PathVariable byte z, @PathVariable int x, @PathVariable int y, HttpServletResponse response) {
        //构造一个MvtBuilder对象
        MvtBuilder mvtBuilder = new MvtBuilder(z, x, y, geometryFactory);
        //向mvt中添加layer
        MvtLayer layer = mvtBuilder.getOrCreateLayer("province-polygon");
        //向layer中添加feature
        for (Feature feature : areaFeatureCollection.getFeatures()) {
            //这里简单地从内存中取数据并判断其是否与瓦片有交集，实际运用中可从数据库查询，例如postgis的ST_intersects函数
            if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {
                layer.addFeature(feature);
            }
        }
        //如法炮制添加layer
        layer = mvtBuilder.getOrCreateLayer("province-line");
        for (Feature feature : lineFeatureCollection.getFeatures()) {
            if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {
                layer.addFeature(feature);
            }
        }
        //如法炮制添加layer
        layer = mvtBuilder.getOrCreateLayer("province-point");
        for (Feature feature : pointFeatureCollection.getFeatures()) {
            if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {
                layer.addFeature(feature);
            }
        }
        //数据添加完毕，转为
        byte[] bytes = mvtBuilder.toBytes();
        String vtContentType = "application/octet-stream";
        exportByte(bytes, vtContentType, response);
    }
    //将bytes写进HttpServletResponse
    private void exportByte(byte[] bytes, String contentType, HttpServletResponse response) {
        response.setContentType(contentType);
        try (OutputStream os = response.getOutputStream()) {
            os.write(bytes);
            os.flush();
        } catch (org.apache.catalina.connector.ClientAbortException e) {
            //地图移动时客户端主动取消， 产生异常"你的主机中的软件中止了一个已建立的连接"，无需处理
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
